package com.atguigu.tingshu.user.init;

import jakarta.annotation.PostConstruct;
import lombok.extern.log4j.Log4j;
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @Author GQS @Date 2024/11/3/21:51 @Description
 * rabbitMQ的可靠性投递的配置
 */
@Component
@Log4j2
public class RabbitConfirmAndReturnInit implements
        RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnsCallback
{

  @Autowired
  private RabbitTemplate rabbitTemplate;


  /**
   * 配置可靠性投递
   */
  @PostConstruct
  public void init(){
    rabbitTemplate.setMandatory(true); // 开启强制路由模式
    // 开启后 如果通过RabbitTemplate发送的消息无法被路由到任何队列
    // RabbitMQ会向消息的发送者返回一个未路由消息（UnRoutable Message）的回调函数
    rabbitTemplate.setConfirmCallback(this::confirm);
    rabbitTemplate.setReturnsCallback(this::returnedMessage);
  }
  /**
   * confirm模式的回调函数: 是否抵达交换机都会触发
   * @param correlationData: 消息元数据,记录消息的编号,确认消息是否被反复发送(重复发送可以用这个来进行校验)
   * @param b: 是否抵达了交换机
   * @param s: 没有抵达的错误是什么,抵达了就是null
   */
  @Override
  public void confirm(CorrelationData correlationData, boolean b, String s) {
    if(!b){
      //记录消息到日志/redis/mysql...
      log.error("消息没有抵达交换机,失败的原因为:" + s);
    }
  }

  /***
   * returnedMessage模式的回调函数: 不抵达队列才触发
   * @param returnedMessage
   */
  @Override
  public void returnedMessage(ReturnedMessage returnedMessage) {
    //错误码
    int replyCode = returnedMessage.getReplyCode();
    //错误信息
    String replyText = returnedMessage.getReplyText();
    //交换机
    String exchange = returnedMessage.getExchange();
    //routingKey
    String routingKey = returnedMessage.getRoutingKey();
    //message
    Message message = returnedMessage.getMessage();
    //记录
    log.error("消息抵达了交换机,但是没有抵达队列,失败的错误码为:{}," +
                      "原因为:{}, " +
                      "交换机为:{}, " +
                      "routingKey为{}, " +
                      "消息内容为: {}",
              replyCode,
              replyText,
              exchange,
              routingKey,
              new String(message.getBody()));
  }
}
